package com.xb.loan.cashier.biz.pay.alipay;

import com.xb.loan.cashier.biz.pay.alipay.config.AlipayConfig;
import com.xb.loan.cashier.biz.pay.alipay.util.AlipayCore;
import com.xb.loan.cashier.biz.pay.alipay.util.AlipayNotify;
import com.xb.loan.cashier.biz.pay.alipay.util.AlipaySubmit;
import com.xb.loan.cashier.biz.util.FileUtil;
import com.xb.loan.cashier.biz.util.MD5;
import com.xb.loan.cashier.service.constant.ICashierEnumConst;
import org.apache.commons.io.FileUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.nutz.http.Http;
import org.nutz.http.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 支付宝工具类方法
 *
 */
public class AlipayPayment {
    //支付宝模块(接口)常量
    public final static String MODULE_SINGLE_TRADE_QUERY = "single_trade_query";//单笔查询
    public final static String MODULE_NOTIFY_VERIFY = "notify_verify";//通知验证
    public final static String BPTB_UNFREEZE_NOTIFY = "bptb_unfreeze_notify";//余额不足通知
    public final static String BPTB_RESULT_NOTIFY = "bptb_result_notify";//结果通知
    
    //支付宝通知状态常量
    public final static String TRADE_FINISHED = "TRADE_FINISHED";
    public final static String TRADE_SUCCESS = "TRADE_SUCCESS";
    public final static String TRADE_CLOSED = "TRADE_CLOSED";
    public final static String TRADE_NOT_EXIST = "TRADE_NOT_EXIST";
    
    
    public static final String TRANSCODE_TYPE_ZZ = "3011";//转账（含红包、集分宝等）
    public static final String TRANSCODE_TYPE_SF = "3012";//收费
    public static final String TRANSCODE_TYPE_CZ = "4003";//充值
    public static final String TRANSCODE_TYPE_TX = "5004";//提现(对应系统提现)
    public static final String TRANSCODE_TYPE_TP = "5103";//退票
    public static final String TRANSCODE_TYPE_ZXZF = "6001";//在线支付(对应系统的充值)
    
    
    private static final Logger logger = LoggerFactory.getLogger(AlipayPayment.class);
    
    /**
     * 批量付款到银行账户-上传付款文件无密接口
     * @param fullFileName
     * @param partner
     * @param signType
     * @param signKey
     * @param payUrl
     * @throws Exception
     */
    public static boolean bptb_pay_file(String fullFileName, String partner, String signType, String signKey, String payUrl, String notifyUrl) throws Exception {
    	logger.info("bptb_pay_file 接收到参数：fullFileName="+fullFileName+",partner="+partner+",signType="+signType+",signKey="+signKey+",payUrl="+payUrl+",notifyUrl="+notifyUrl);
        String digest_bptb_pay_file = AlipayCore.getAbstract(fullFileName, signType);//文件摘要
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("service", "bptb_pay_file");
        sParaTemp.put("partner", partner);
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
        sParaTemp.put("file_digest_type", signType);
        sParaTemp.put("digest_bptb_pay_file", digest_bptb_pay_file);
        sParaTemp.put("notify_url", notifyUrl);
        sParaTemp.put("bussiness_type", ICashierEnumConst.CashierBankDelayType.T0.getCode());
        String sHtmlText = AlipaySubmit.buildRequest("bptb_pay_file", fullFileName, sParaTemp, signType, signKey, payUrl);
        if("文件上传成功!".equals(sHtmlText)){
            logger.info("bptb_pay_file_confirm success!filename="+fullFileName);
            return true;
        }else{
            logger.error("bptb_pay_file_confirm fail, msg="+sHtmlText+" filename="+fullFileName);
            return false;
        }
    }
    
    /**
     * 批量付款到银行账户-文件查询接口
     * @param fileName
     * @param partner
     * @param signType
     * @param signKey
     * @param payUrl
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public static boolean bptb_file_query(String fileName, String partner, String signType, String signKey, String payUrl) throws Exception {
        //把请求参数打包成数组
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("service", "bptb_file_query");
        sParaTemp.put("partner", partner);
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
        sParaTemp.put("file_name", fileName);
        
        //建立请求
        String strUrl = AlipaySubmit.buildRequest("", "", sParaTemp, signType, signKey, payUrl);
        SAXReader reader = new SAXReader();
        Document doc = reader.read(new ByteArrayInputStream(strUrl.getBytes("UTF-8")));

        List<Node> nodeList = doc.selectNodes("//alipay/*");

        for (Node node : nodeList) {
            // 截取部分不需要解析的信息
            if (node.getName().equals("is_success")) {
                if(node.getText().equals("T")){
                   return true;
                }
                return false;
            }
        }
        return false;
    }

    /**
     * 批量付款到银行账户-下载付款结果文件
     * @param fileName
     * @param partner
     * @param signType
     * @param signKey
     * @param payUrl
     * @return
     * @throws IOException
     */
    public static boolean bptb_result_file(String fileName, String resultFilePath, String partner, String signType, String signKey, String payUrl) throws IOException {
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("service", "bptb_result_file");
        sParaTemp.put("partner", partner);
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
        sParaTemp.put("file_name", fileName);// 文件名
        sParaTemp.put("date", null);//查询日期,文件名和查询日期不能同时为空
        logger.info("bptb_result_file aipayParams="+sParaTemp.toString()+",signType="+signType+",signKey="+signKey+",payUrl="+payUrl);
        //建立请求
        String url = AlipaySubmit.buildRequest(sParaTemp,"get","确认", signType, signKey, payUrl);
        logger.info("bptb_result_file url="+url);
        InputStream in = null;
        // 解压缩
        Response response = Http.get(url);
        String contextType = response.getHeader().get("Content-Type");

        String resultFileName = FileUtil.nameResultFile(fileName);
        //根据contextType判断响应是stream还是text/html
        if (contextType != null && contextType.indexOf("application/octet-stream") != -1) {
            // 成功
            in = response.getStream();
            if(in != null){
                String zipFile = resultFilePath + "/" + resultFileName;
                FileUtils.copyInputStreamToFile(in, new File(zipFile));
                FileUtil.unzipFirstFile(zipFile, resultFilePath, "\\.csv", fileName);
                logger.info("get result file:" + zipFile);
                return true;
            }
        } else {
            // 失败
            String errMsg = response.getContent();
            logger.info("get result file: fileName="+resultFileName +","+ errMsg);
            throw new IOException(errMsg);
        }
        return false;
    }
    
    /**
     * 验证支付宝通知
     * @param request
     * @param partner
     * @param sign_type
     * @param sign_key
     * @return
     */
    public static boolean notify_verify(HttpServletRequest request, String partner, String sign_type, String sign_key, String payUrl){
        Map<String,String> params = new HashMap<String,String>();
        Enumeration<String> paramNames = request.getParameterNames();
        if(paramNames==null){
            logger.warn("notify_verify() msg=参数为空");
            return false;
        }
        while(paramNames.hasMoreElements()){
            String paramName = paramNames.nextElement();
            params.put(paramName, request.getParameter(paramName));
        }
        return notify_verify(params, partner, sign_type, sign_key, payUrl);
    }
    
    /**
     * 验证支付宝通知
     * @param params
     * @param partner
     * @param sign_type
     * @param sign_key
     * @return
     */
    public static boolean notify_verify(Map<String,String> params, String partner, String sign_type, String sign_key, String payUrl){
        if(payUrl.lastIndexOf("?") != payUrl.length()-1){
        	payUrl = payUrl + "?";
        }
    	String verifyUrl = payUrl+"service=notify_verify&";
        return AlipayNotify.verify(params,sign_type,sign_key,partner,verifyUrl);
    }
    
    /**
     * 批量付款到银行账户-下载退票结果文件接口
     * @param day yyyyMMdd
     * @param fileName
     * @param resultFilePath
     * @param partner
     * @param signType
     * @param signKey
     * @param payUrl
     * @return
     * @throws IOException
     */
    public static boolean bptb_refund_file(String day, String fileName, String resultFilePath, String partner, String signType, String signKey, String payUrl) throws IOException {
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("service", "bptb_refund_file");
        sParaTemp.put("partner", partner);
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
        sParaTemp.put("date", day);
        
        //建立请求
        String url = AlipaySubmit.buildRequest(sParaTemp,"get","确认", signType, signKey, payUrl);
        InputStream in = null;
        // 解压缩
        Response response = Http.get(url);
        String contextType = response.getHeader().get("Content-Type");
        if (contextType.indexOf("application/octet-stream") != -1) {
            // 成功
            in = response.getStream();
            if(in != null){
                String resultFileName = FileUtil.nameResultFile(fileName);
                String zipFile = resultFilePath + "/" + resultFileName;
                FileUtils.copyInputStreamToFile(in, new File(zipFile));
                FileUtil.unzipFirstFile(zipFile, resultFilePath, "\\.csv", fileName);
                logger.info("get result file -------" + zipFile);
                return true;
            }
        } else {
            // 失败
            String errMsg = response.getContent();
            logger.info("get result file -------" + errMsg);
        }
        
        return false;
    }
    
    /**
     * 账务明细分页查询接口接入页
     * @param pageNo
     * @param pageSize
     * @param transCode
     * @param startTime
     * @param endTime
     * @param partner
     * @param signType
     * @param signKey
     * @param payUrl
     * @return
     * @throws Exception
     */
    public static String account_page_query(String pageNo , String pageSize, String transCode, String startTime, String endTime, String partner, String signType, String signKey, String payUrl) throws Exception {
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("service", "account.page.query");
        sParaTemp.put("partner", partner);
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
        sParaTemp.put("page_no", pageNo);
        sParaTemp.put("page_size", pageSize);
        sParaTemp.put("trans_code", transCode);
        sParaTemp.put("gmt_start_time", startTime);
        sParaTemp.put("gmt_end_time", endTime);
        return AlipaySubmit.buildRequest("", "", sParaTemp, signType, signKey, payUrl);
    }
    
    /**
     * 账务明细分页查询接口接入页-验签
     * @param data
     * @param signKey
     * @param charset
     * @return
     */
    public static final boolean account_page_query_validate(String data, String signKey, String charset){
    	logger.info("account_page_query_validate data="+data+",signKey="+signKey+",charset="+charset);
        try {
            Document document = DocumentHelper.parseText(data);
            String isSucc = document.selectSingleNode("/alipay/is_success").getText();
            if ("F".equals(isSucc)) {
            	String error = document.selectSingleNode("/alipay/error").getText();
            	logger.info("account_page_query_validate 验签异常   error="+error);
            	return false;
			}
            String sign = document.selectSingleNode("/alipay/sign").getText();
            
            Element wrapper = (Element) document.getRootElement().selectSingleNode(
            "/alipay/response/account_page_query_result");
            String hasNextPage = wrapper.elementText("has_next_page");
            String pageNo = wrapper.elementText("page_no");
            String pageSize = wrapper.elementText("page_size");
            Element accountLogList = wrapper.element("account_log_list");
            OutputFormat format = new OutputFormat();
            // expand <xxx /> to <xxx></xxx>
            format.setExpandEmptyElements(true); //一定要设置
            StringWriter accountLogListContent = new StringWriter();
            XMLWriter writer = new XMLWriter(accountLogListContent, format);
            writer.write(accountLogList);
            String payload = String.format(
            "account_log_list=%s&has_next_page=%s&page_no=%s&page_size=%s",
            accountLogListContent, hasNextPage, pageNo, pageSize);
            return sign.equals(MD5.sign(payload, signKey, charset));
        } catch (Exception e) {
            logger.error("account_page_query_validate throws a exception", e);
        }
        return false;
    }
    
    /**
     * 单笔交易查询
     * @param partner
     * @param orderId
     * @param signType
     * @param signKey
     * @param queryUrl
     * @return
     * @throws Exception
     * 2015-9-21 by lottery
     */
    public static String singleTradeQuery(String partner, String orderId, String signType, String signKey, String queryUrl) throws Exception {
        Map<String,String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("service", MODULE_SINGLE_TRADE_QUERY);   //service
        sParaTemp.put("partner", partner);  //合作者身份ID
        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
        sParaTemp.put("out_trade_no", orderId); //商户订单号
        return AlipaySubmit.buildRequest("", "", sParaTemp, signType, signKey, queryUrl);
    }
    
    public static void main(String[] args) throws Exception {
    	bptb_result_file("1003_1_1607051722100061.csv", "e:/", "2088101985264251", "MD5", "6beartfv6qw2xext573967j19ngwjg8h", "https://mapi.alipay.com/gateway.do");
//    	String result = singleTradeQuery("2088101985264251", "1607051010150890", "MD5", "6beartfv6qw2xext573967j19ngwjg8h", "https://mapi.alipay.com/gateway.do");
//    	System.out.println(bptb_file_query("1003_1_1607051722100061.csv", "2088101985264251", "MD5", "6beartfv6qw2xext573967j19ngwjg8h", "https://mapi.alipay.com/gateway.do"));
//    	String result = account_page_query("", "", "6001", "2016-07-05 00:00:00", "2016-07-05 17:00:00", "2088101985264251", "MD5", "6beartfv6qw2xext573967j19ngwjg8h", "https://mapi.alipay.com/gateway.do");
	}
}
